/*
 * @Author: Black / 李来然
 * @Date: 2021-12-07 16:21:46
 * @LastEditors: Black / 李来然
 * @LastEditTime: 2022-01-05 09:22:26
 * @Description: ecjrjs idCard TS重构
 */
import { BaseIO } from "./baseIO";
import { getModeFuncRet, Result, ResultFail, ResultOk, RetResult } from "../tools/modHelper";

type CustonIdCardInfo = {
    Address: string,
    BackImage: string,
    Born: string,
    EnName: string,
    EnNation: string,
    FrontImage: string,
    GrantDept: string,
    IDCardNo: string,
    IssuesTimes:string,
    Name: string,
    Nation: string,
    NewAddress: string,
    PassPortNo: string,
    PhotoFileName: string,
    Sex: string,
    Type: string,
    UserLifeBegin: string,
    UserLifeEnd: string,
    ValidPeriod: string,

    FrontImageBase64: string,
    BackImageBase64: string,
    PhotoFileNameBase64: string
};

 type NewIdCardInfo = CustonIdCardInfo & IdcardInfo;

interface IdCardState { }
interface IdCardCapability { }

export type InsertFnRet = "CardInserted" | "ChipDataReceived" | "CardAcceptCancelled";

type Insertfn = (param: RetResult<InsertFnRet>) => void;

type IdcardInfo = {
    Address: string,
    BackImage: string,
    Born: string,
    FrontImage: string,
    GrantDept: string,
    IDCardNo: string,
    Name: string,
    Nation: string,
    PhotoFileName: string,
    Sex: string,
    UserLifeBegin: string,
    UserLifeEnd: string
};

// 插卡结果
type InsertRet =
    | "Timeout"
    | "DeviceError"
    | "FatalError"
    | "CardInserted"
    | "ChipDataReceived"
    | "CardInvalid"
    | "CardAccepted"
    | "CardAcceptCancelled";

// 取消插卡结果
type CancelInsertRet =
    | "CardAcceptCancelled"
    | "FatalError";

// 复位结果
type ResetRet =
    | "DeviceError"
    | "FatalError"
    | "Timeout"
    | "ResetComplete";

export class IdCard extends BaseIO<IdCardState, IdCardCapability>{
    constructor(modName: string, mod: any) {
        super(modName, mod);
    }

    /**
     *	插入卡片
     *  @param   {string} TrackMap 读取磁道或者芯片数据，如“2,3,CHIP",可以组合传入
     *  @param   {number} timeout 超时时间，超时时间，单位为毫秒，-1表示无限等待
     *  @param   {function} __call_fn 事件回调  CardInserted ChipDataReceived 事件触发
     *  @returns {Promise<json>} - {mod:this.name, ret: '', param: arg}
     *  @return  {String} return.ret 事件 <br> CardInserted - 卡插入 <br> ChipDataReceived - 芯片卡插入<br> CardAccepted - 卡被识别，读卡成功<br> CardAcceptCancelled - 读卡取消<br> Timeout - 读卡超时 <br>FatalError - 失败 <br> DeviceError - 设备故障 <br> CardInvalid - 无效卡 <br>
     *  @return  {Array} return.param - 事件参数，ChipDataReceived-param[1] - 芯片上电数据
     */
    Insert(strTrackMap: string, timeout: number, __call_fn: Insertfn | null = null) {
        Trace(EC_INFO, `-->IdCard:insert(${strTrackMap},${timeout})`);
        this.setCurrentMethod("Insert");
        this.removeMethodBindEvt("Insert");
        return new Promise<RetResult<InsertRet>>((resolve, reject) => {
            const Timeout = (...args: any[]) => {
                Trace(EC_INFO, `<--${this.modName}:insert Timeout`);
                resolve(getModeFuncRet(this.modName, "Timeout", args));
            };
            const DeviceError = (...args: any[]) => {
                Trace(EC_INFO, `<--${this.modName}:insert DeviceError`);
                resolve(getModeFuncRet(this.modName, "DeviceError", args));
            };
            const FatalError = (...args: any[]) => {
                Trace(EC_INFO, `<--${this.modName}:insert FatalError`);
                resolve(getModeFuncRet(this.modName, "FatalError", args));
            };
            const CardInserted = (...args: any[]) => {
                Trace(EC_INFO, `--${this.modName}:insert CardInserted`);
                if (__call_fn)
                    __call_fn(getModeFuncRet(this.modName, "CardInserted", args));
            };
            const ChipDataReceived = (...args: any[]) => {
                Trace(EC_INFO, `--${this.modName}:insert ChipDataReceived`);
                if (__call_fn)
                    __call_fn(getModeFuncRet(this.modName, "ChipDataReceived", args));
            };
            const CardInvalid = (...args: any[]) => {
                Trace(EC_INFO, `<--${this.modName}:insert CardInvalid`);
                resolve(getModeFuncRet(this.modName, "CardInvalid", args));
            };
            const CardAccepted = (...args: any[]) => {
                let arg = ['CardAccepted'].concat(args.slice(0));
                Trace(EC_INFO, `<--${this.modName}:insert CardAcceptCancelled`);
                resolve(getModeFuncRet(this.modName, "CardAccepted", arg));
            };
            const CardAcceptCancelled = (...args: any[]) => {
                Trace(EC_INFO, `<--${this.modName}:insert CardAcceptCancelled`);
                reject(getModeFuncRet(this.modName, "CardAcceptCancelled", args));
            };

            this.add("Timeout", Timeout);
            this.add("DeviceError", DeviceError);
            this.add("FatalError", FatalError);
            this.add("CardInserted", CardInserted);
            this.add("ChipDataReceived", ChipDataReceived);
            this.add("CardInvalid", CardInvalid);
            this.add("CardAccepted", CardAccepted);
            this.add("CardAcceptCancelled", CardAcceptCancelled);

            if (strTrackMap == undefined) strTrackMap = '3';
            if (timeout == undefined) timeout = -1;
            this.mod.AcceptAndReadTracks(strTrackMap, timeout, (ret: string) => {
                if (parseInt(ret) !== 0) {
                    Trace(EC_INFO, `<--${this.modName}:insert ret=${ret}`);
                    resolve(getModeFuncRet(this.modName, "FatalError"));
                }
            });
        }).then((value) => {
            this.removeMethodBindEvt("Insert");
            __call_fn = null;
            return value;
        }).catch((err) => {
            this.removeMethodBindEvt("Insert");
            this.remove("CardAcceptCancelled", err);
            return err;
        });
    }

    
    GetTrack3() {
        Trace(EC_INFO, `-->IdCard:getTrack3`);
        this.setCurrentMethod("GetTrack3");
        this.removeMethodBindEvt("GetTrack3");
        return new Promise<Result<NewIdCardInfo>>((resolve, reject) => {
            this.mod.GetTrack3((track: string) => {
                type S = {
                    [s: string]: string
                }
                let obj: S = {};
                let resultOK: ResultOk = {
                    Result: 'OK'
                }
                let resultFail: ResultFail = {
                    Result: 'FAIL'
                }

                const x: Uint8Array = new Uint8Array(eval(track));
                const str: string = new TextDecoder('gbk').decode(x);
                if(str == ' ') {
                    resolve(resultFail);
                }
                const arry = str.split(',');
                for (let i = 0; i < arry.length; i++) {
                    const arr: string[] = arry[i].split('=');
                    obj[arr[0]] = arr[1];
                }
                let nr = Object.assign(resultOK, obj as NewIdCardInfo)
                resolve(nr);
            });
        }).then((value) => {
            this.removeMethodBindEvt("GetTrack3");
            return value;
        })
    }

    /**
     * 取消卡插入动作
     * @returns {Promise<json>} - {mod:this.name, ret: '', param: arg}
     * @return {String} return.ret 事件 <br> CardAcceptCancelled - 取消成功
     * @return {Array} return.param - 事件参数 无
     */
    CancelInsert() {
        Trace(EC_INFO, '-->IdCard:cancelInsert');
        this.setCurrentMethod("CancelInsert");
        this.removeMethodBindEvt("CancelInsert");
        return new Promise<RetResult<CancelInsertRet>>((resolve, reject) => {
            const CardAcceptCancelled = (...args: any[]) => {
                Trace(EC_INFO, `<--${this.modName}:insert CardAcceptCancelled`);
                resolve(getModeFuncRet(this.modName, "CardAcceptCancelled", args));
            };

            this.add('CardAcceptCancelled', CardAcceptCancelled);

            this.mod.CancelAccept((ret: string) => {
                if (parseInt(ret) !== 0) {
                    Trace(EC_INFO, `<--${this.modName}:cancelInsert ret=${ret}`);
                    resolve(getModeFuncRet(this.modName, "FatalError"));
                }
            });
        }).then((value) => {
            this.removeMethodBindEvt("CancelInsert");
            return value;
        });
    }

    /**
     *	复位
     * @param    {string} action 复位动作，“RETRACT”:回收卡  “EJECT”: 退卡
     * @returns  {Promise<json>} {mod:this.name, ret: '', param: arg}
     * @return   mod  模块名
     * @return   ret  事件名：<br> ResetComplete - 复位成功 <br> FatalError - 失败 <br> DeviceError - 设备故障 <br> Timeout - 超时 <br> 
     * @return   {number}  param   返回值
     */
    Reset(action: string) {
        Trace(EC_INFO, '-->IdCard:reset');
        this.setCurrentMethod("Reset");
        this.removeMethodBindEvt("Reset");
        Trace(EC_INFO, `-->${this.modName}:reset`);
        return new Promise<RetResult<ResetRet>>((resolve, reject) => {
            const DeviceError = (...args: any[]) => {
                Trace(EC_INFO, `<--${this.modName}:reset DeviceError`);
                resolve(getModeFuncRet(this.modName, "DeviceError", args));
            };
            const FatalError = (...args: any[]) => {
                Trace(EC_INFO, `<--${this.modName}:reset FatalError`);
                resolve(getModeFuncRet(this.modName, "FatalError", args));
            };
            const Timeout = (...args: any[]) => {
                Trace(EC_INFO, `<--${this.modName}:reset Timeout`);
                resolve(getModeFuncRet(this.modName, "Timeout", args));
            };
            const ResetComplete = (...args: any[]) => {
                Trace(EC_INFO, `<--${this.modName}:reset ResetComplete`);
                resolve(getModeFuncRet(this.modName, "ResetComplete", args));
            };

            this.add('DeviceError', DeviceError);
            this.add('FatalError', FatalError);
            this.add('Timeout', Timeout);
            this.add('ResetComplete', ResetComplete);

            this.mod.Reset(action, (ret: number) => {
                if (ret != 0) {
                    Trace(EC_INFO, `-->${this.modName}:reset ret=${ret}`);
                    resolve(getModeFuncRet(this.modName, "FatalError"));
                }
            });
        }).then((value) => {
            this.removeMethodBindEvt("Reset");
            return value;
        });
    }
}
